package com.ctl.utils.mongo;

import org.bson.Document;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.beans.PropertyDescriptor;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


/**
 * <p>Title: Bean2Document</p>
 * <p>Description: </p>
 * <p>Copyright: Copyright (c) 2019</p>
 * <p>Company: www.ctl.com</p>
 * bean转换为Document mongoTemplate.getCollection("device").insertOne(document);
 * @author ctl
 * @version 1.1
 * @date 2022-11-17 17:58
 */

public class Bean2Document<T> {

    //字段前缀
//    private static final char COLUMN_PREFIX = 'F';
    private static final String COLUMN_PREFIX = "";
    //单词分隔符
//    private static final char UNDER_LINE = '_';
    private static final String UNDER_LINE = "";
    //字段属性映射
    private transient Map<String, PropertyDescriptor> mappedFields;

    private static Map<Class<?>, Bean2Document> mapperMap = new ConcurrentHashMap<>();

    public Bean2Document(Class<T> mappedClass) {
        initialize(mappedClass);
    }

    /**
     * 创建一个新的Bean2Document类
     *
     * @param mappedClass 需要映射的实体类
     */
    @SuppressWarnings("unchecked")
    public static <T> Bean2Document<T> newInstance(Class<T> mappedClass) {
        Bean2Document mapper = mapperMap.get(mappedClass);
        if (mapper == null) {
            mapper = new Bean2Document<>(mappedClass);
            mapperMap.put(mappedClass, mapper);
        }
        return (Bean2Document<T>) mapper;
    }

    /**
     * 将实体属性初始化到mappedFields中
     *
     * @param mappedClass 需要初始化的实体类
     */
    @SuppressWarnings("Duplicates")
    protected void initialize(Class<T> mappedClass) {
        this.mappedFields = new HashMap<>();
        PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass);
        for (PropertyDescriptor pd : pds) {
            if (pd.getWriteMethod() != null) {
//                this.mappedFields.put(pd.getName().toUpperCase(), pd);
                this.mappedFields.put(pd.getName(), pd);
            }
        }
    }

    /**
     * 将实体字段名转换为表字段名
     *
     * @param name 实体字段
     * @return 返回对应表字段名
     */
    @SuppressWarnings("Duplicates")
    private String underscoreName(String name) {
        if (!StringUtils.hasLength(name)) {
            return "";
        }
        // 添加字段前缀
        StringBuilder result = new StringBuilder();
        if (!ObjectUtils.isEmpty(COLUMN_PREFIX)) {
            result.append(COLUMN_PREFIX).append(UNDER_LINE);
        }
//        result.append(name.substring(0, 1).toUpperCase());
        result.append(name.substring(0, 1));
        for (int i = 1; i < name.length(); i++) {
            String ss = name.substring(i, i + 1);
//            String slc = ss.toUpperCase();
            String slc = ss;
            if (ss.equals(slc)) {
                result.append(UNDER_LINE).append(slc);
            } else {
                result.append(slc);
            }
        }
        return result.toString();
    }

    /**
     * 将实体数据格式转换为Document格式
     *
     * @param data 实体数据
     * @return Document格式数据
     */
    public Document toDocument(T data) {
        if (data == null) {
            return null;
        }

        Document document = new Document();
        BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(data);
        for (PropertyDescriptor pd : this.mappedFields.values()) {
            Object value = bw.getPropertyValue(pd.getName());
            String underscoredName = underscoreName(pd.getName());
            document.put(underscoredName, value);
        }
        return document;
    }
}